home *** CD-ROM | disk | FTP | other *** search
/ Power CD-ROM!! 8 / Power CD-ROM 8.iso / prgmming / maxlib10 / maxlib.doc < prev    next >
Encoding:
Text File  |  1994-10-29  |  49.9 KB  |  1,299 lines

  1.  
  2.  
  3.  
  4.  
  5.                    MAXLIB.DOC
  6.                    ─────────────────────────────────
  7.                    Documentation for MAXLIB For PB
  8.  
  9.  
  10.  
  11.  
  12.  
  13.  
  14.  
  15.  
  16.  
  17.  
  18.                                   Copyright 1994 Brian McLaughlin
  19.                      ────────────────────────────────────────────
  20.                                               All Rights Reserved
  21.  
  22.  
  23.  
  24.  
  25.  
  26.  
  27.  
  28.                          TABLE OF CONTENTS
  29.  
  30.                                                       line number
  31.  
  32.     INTRODUCTION .......................................   62
  33.  
  34.          About This Document ...........................  105
  35.          MAXLIB For PB is Shareware ....................  124
  36.          PBFiles is Yours - Free! ......................  158
  37.          Requirements for Using MAXLIB For PB ..........  191
  38.          Limited Warranty ..............................  227
  39.  
  40.  
  41.     HOW TO USE MAXLIB FOR PB
  42.  
  43.          Using $LINK and $INCLUDE ......................  265
  44.          Using MAXLIB in the IDE  ......................  310
  45.          Getting Started with MAXFiles .................  340
  46.          Getting Started with MAXArray .................  537
  47.          Handling Errors ...............................  711
  48.  
  49.  
  50.     GENERAL TOPICS
  51.  
  52.          About File Pointers ...........................  852
  53.          About Expanded Memory .........................  967
  54.          About DOS STDxxx Devices ...................... 1040
  55.          Avoiding Problems With HUGE Arrays ............ 1116
  56.          Safeguarding Your Data ........................ 1218
  57.  
  58.  
  59.  
  60.  
  61.  
  62.     INTRODUCTION
  63.  
  64.  
  65.     MAXLIB For PB is designed to make your programs faster and more
  66.     capable than ever before.  And because MAXLIB For PB builds upon
  67.     familiar BASIC commands and ideas, it is easy to learn and easy
  68.     to incorporate into your code.
  69.  
  70.     MAXLIB for PB consists of two complete sets of routines:
  71.     MAXFiles and MAXArray.  Both of them provide you with easy, but
  72.     sophisticated memory management.  Each one presents you with a
  73.     different interface and its own set of strengths, so you can
  74.     choose the one that best suits your needs.
  75.  
  76.     The 25 commands in MAXFiles are patterned after the BASIC
  77.     commands used with disk files (especially files opened for
  78.     binary access).  MAXFiles speeds up your program's disk file
  79.     access by loading disk files into expanded memory as they are
  80.     opened.  From then on, your program will read from and write to
  81.     the file in expanded memory, which is much faster than if the
  82.     file were accessed directly from the disk.
  83.  
  84.     MAXFiles takes advantage of whatever expanded memory is
  85.     available (if any) and will automatically fall back to using
  86.     disk space when expanded memory is exhausted.  For that reason,
  87.     programs written using MAXFiles can run on computers with no
  88.     expanded memory, or with very little, or a lot -- all using the
  89.     same few lines of code!
  90.  
  91.     The 16 commands in MAXArray are patterned after the BASIC
  92.     commands used to dimension and manage arrays in conventional
  93.     memory.  With MAXArray you can create and manage arrays that are
  94.     much larger than 640K, right up to the limit of available EMS
  95.     memory, without having to learn all the intricacies of expanded
  96.     memory management.
  97.  
  98.     MAXArray lets you copy entire files or conventional arrays into
  99.     and out of expanded memory using a single line of code!  And
  100.     because it has less internal complexity, MAXArray is even faster
  101.     than MAXFiles.
  102.  
  103.  
  104.  
  105.     ABOUT THIS DOCUMENT
  106.  
  107.  
  108.     This file (MAXLIB.DOC) discusses topics of general interest to
  109.     anyone using MAXLIB For PB.  Technical details for each routine
  110.     are available in the file MAXLIB.REF.
  111.  
  112.     In this document the terms "expanded memory" and "EMS" are used
  113.     (somewhat loosely) to mean the same thing.
  114.  
  115.     In this document the term "EMS file" refers to a file loaded
  116.     into expanded memory and being accessed there, as opposed to a
  117.     file that is located on a disk drive.  The term "EMS array"
  118.     refers to an array stored in expanded memory and accessed there,
  119.     as opposed to an array stored in conventional memory.
  120.  
  121.  
  122.  
  123.  
  124.     MAXLIB FOR PB IS SHAREWARE
  125.  
  126.  
  127.     MAXLIB For PB is shareware.  It is not free software.  You are
  128.     expected to pay for MAXLIB For PB, if you decide to keep it and
  129.     use it.
  130.  
  131.     Shareware may be freely copied and distributed, eliminating the
  132.     high distribution costs associated with most commercial
  133.     software.  The shareware method also allows you to evaluate
  134.     whether MAXLIB For PB meets your needs and does what it is
  135.     supposed to do, before you pay for it.
  136.  
  137.     Programs you write using this evaluation copy of MAXLIB For PB
  138.     must be for the purpose of evaluation only.  Under no
  139.     circumstances are you allowed to compile and distribute programs
  140.     incorporating MAXLIB For PB, unless you have the appropriate
  141.     license.  To obtain an appropriate license you must register
  142.     MAXLIB For PB.
  143.  
  144.     All the information you need in order to register MAXLIB For PB,
  145.     including what it costs and what you get when you register, is
  146.     contained in the file REGISTER.TXT.  You'll find an easy to
  147.     print order form in the file ORDER.FRM.
  148.  
  149.     MAXLIB For PB represents the end product of hundreds of hours of
  150.     skilled labor, spent in designing, programming, testing and
  151.     documentation.  I believe MAXLIB For PB will meet your
  152.     professional standards and that it compares well to any
  153.     programming library of its kind.  I hope you agree.
  154.  
  155.  
  156.  
  157.  
  158.     PBFILES IS YOURS - FREE!
  159.  
  160.  
  161.     As part of the package distributed with MAXLIB For PB, you will
  162.     find a file called PBFILES.ZIP.  It contains the source code,
  163.     object file and documentation for a file i/o library called
  164.     PBFiles.  PBFiles is functionally identical to MAXFiles, except
  165.     it has no support for emulated file i/o in expanded memory.
  166.  
  167.     I have placed the source code for PBFiles into the public
  168.     domain.  That means PBFiles is free for you to use as you wish.
  169.     It requires no payment or fees of any kind.  PBFILES.ZIP also
  170.     includes PBFILES.DOC, a copyrighted file you may freely
  171.     distribute.
  172.  
  173.     The only conditions I have placed on copying PBFILES.DOC is that
  174.     it must not be altered, and it must always be accompanied by
  175.     unaltered copies of the source code file and two other files.
  176.  
  177.     I wrote PBFiles and included it with MAXLIB For PB so that the
  178.     code you write for the purpose of evaluating MAXFiles will
  179.     remain useful, even if you decide not to register MAXLIB.  This
  180.     should adequately compensate you for the time and effort you
  181.     spend in evaluating MAXLIB For PB.
  182.  
  183.     It is simple to convert any code you have written for MAXFiles
  184.     to use PBFiles instead.  If you change your mind later and
  185.     decide to register MAXLIB For PB, all the code you wrote using
  186.     PBFiles will painlessly convert back for use with MAXLIB For PB.
  187.  
  188.  
  189.  
  190.  
  191.     REQUIREMENTS FOR USING MAXLIB FOR PB
  192.  
  193.  
  194.     To use MAXLIB For PB you must have a copy of the PowerBASIC 3.0b
  195.     compiler or later.  I have tested MAXLIB For PB with the
  196.     PowerBASIC 3.0a release and found that because of bugs in that
  197.     compiler, MAXLIB For PB is not stable.
  198.  
  199.     You must also have a copy of the library file MAXLIB.PBL which
  200.     is included as part of MAXLIB For PB.
  201.  
  202.     MAXLIB is written in 8086 assembly language and should run on
  203.     any 80x86-based computer.  MAXLIB only uses DOS functions that
  204.     are present in every version of DOS numbered v2.1 and later.
  205.  
  206.     The MAXFiles portion of MAXLIB For PB is designed to operate
  207.     with or without expanded memory, but it requires the presence of
  208.     an EMM driver v4.0 (or better) for the EMS features to be
  209.     active.
  210.  
  211.     The MAXArray portion of MAXLIB For PB requires the presence of
  212.     expanded memory.  MAXArray should work with all versions of EMM
  213.     driver software numbered v3.0 and later.
  214.  
  215.     NOTE: Although MAXLIB For PB includes some support for networks,
  216.     it has not been tested in a networked environment.  If you
  217.     intend to use MAXLIB For PB on a network, you should test your
  218.     code thoroughly to ensure it is network-safe.
  219.  
  220.     PowerBASIC is a trademark of PowerBASIC, Inc of Carmel,
  221.     California.
  222.  
  223.  
  224.  
  225.  
  226.  
  227.     LIMITED WARRANTY
  228.  
  229.  
  230.     THIS COPY OF MAXLIB FOR PB (THE "SOFTWARE") IS PROVIDED ON AN
  231.     "AS IS" BASIS.  BRIAN MCLAUGHLIN (THE "AUTHOR") DISCLAIMS ALL
  232.     WARRANTIES RELATING TO THE SOFTWARE, WHETHER EXPRESSED OR
  233.     IMPLIED, INCLUDING BUT NOT LIMITED TO ANY IMPLIED WARRANTIES OF
  234.     MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  NEITHER
  235.     THE AUTHOR NOR ANYONE ELSE WHO HAS BEEN INVOLVED IN THE
  236.     CREATION, PRODUCTION, OR DELIVERY OF THE SOFTWARE SHALL BE
  237.     LIABLE FOR ANY INDIRECT, CONSEQUENTIAL, OR INCIDENTAL DAMAGES
  238.     ARISING OUT OF THE USE OR INABILITY TO USE SUCH SOFTWARE, EVEN
  239.     IF THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
  240.     DAMAGES OR CLAIMS.  THE PERSON USING THE SOFTWARE BEARS ALL RISK
  241.     AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE.
  242.  
  243.     This agreement shall be governed by the laws of the State of
  244.     Oregon and shall inure to the benefit of the author and any
  245.     successors, administrators, heirs and assigns.  Any action or
  246.     proceeding brought by either party against the other arising out
  247.     of or related to this agreement shall be brought only in a STATE
  248.     or FEDERAL COURT of competent jurisdiction located in Clackamas
  249.     County, OR.  The parties hereby consent to in personam
  250.     jurisdiction of said courts.
  251.  
  252.  
  253.  
  254.  
  255.  
  256.     HOW TO USE MAXLIB FOR PB
  257.  
  258.  
  259.     This section contains enough information to get you started
  260.     using MAXLIB For PB.  More detailed information is available in
  261.     the file MAXLIB.REF.
  262.  
  263.  
  264.  
  265.     USING $LINK AND $INCLUDE
  266.  
  267.  
  268.     Every program that uses MAXLIB For PB must meet a few simple
  269.     requirements: it must make the library file MAXLIB.PBL available
  270.     to the PB compiler, and it must include declarations for all the
  271.     routines it uses from MAXLIB For PB.
  272.  
  273.     By far the easiest way to meet these requirements is to add two
  274.     simple lines of code near the beginning of your source code.
  275.     The first line uses the $LINK metacommand to incorporate
  276.     MAXLIB.PBL into your program.  You must place this line before
  277.     any executable commands in your source code:
  278.  
  279.  
  280.         $LINK "MAXLIB.PBL"
  281.  
  282.  
  283.     If MAXLIB.PBL is not in the current directory, you must tell PB
  284.     how to find it by including the full path in the the file spec.
  285.     For instance, if MAXLIB.PBL were on a RAM disk designated as
  286.     your D: drive, in a subdirectory named LIB, the full file spec
  287.     would be:
  288.  
  289.  
  290.         $LINK "D:\LIB\MAXLIB.PBL"
  291.  
  292.  
  293.     You will also need to include a second line near the top of your
  294.     source code:
  295.  
  296.  
  297.         $INCLUDE "MAXLIB.BI"
  298.  
  299.  
  300.     MAXLIB.BI contains the declarations for all the routines in
  301.     MAXLIB For PB.  The above line of code above includes those
  302.     declarations in your code.  Again, if MAXLIB.BI is not in the
  303.     current directory, you will need to let PB know how to find it
  304.     by including the full path in the file spec.
  305.  
  306.  
  307.  
  308.  
  309.  
  310.     USING MAXLIB IN THE IDE
  311.  
  312.  
  313.     If you program within the PowerBASIC IDE (called PB.EXE), you
  314.     should realize that the IDE, by default, uses all the EMS
  315.     resources on your computer.
  316.  
  317.     If you do not change this default behavior, there will not be
  318.     any expanded memory available to your programs that use MAXLIB,
  319.     when you compile them and test them from inside the IDE.  With
  320.     no EMS to work with, commands in MAXFiles will always fall back
  321.     to disk access and commands in MAXArray will not work at all.
  322.  
  323.     The same problems apply to running your programs under PBD.EXE.
  324.  
  325.     To change the defaults for PB.EXE or PBD.EXE, you must run
  326.     PBINST.EXE.  Choose the menu item "Limit EMS/XMS usage".  You
  327.     must choose an amount of EMS other than "ALL".
  328.  
  329.     NOTE: If you use EMM386.SYS or another memory manager that uses
  330.     upper memory to simulate both XMS and EMS memory, then you must
  331.     also use PBINST.EXE to limit XMS usage to an amount other than
  332.     "ALL".  If you do not, no EMS memory will be available to your
  333.     program, even if you limit EMS usage to zero.
  334.  
  335.     
  336.  
  337.  
  338.  
  339.  
  340.     GETTING STARTED WITH MAXFILES
  341.  
  342.  
  343.     The information in this section is designed to get you started
  344.     with MAXFiles.  Consult MAXLIB.REF to get answers to specific
  345.     questions about how each routine works.
  346.  
  347.     Disk access is the slowest operation on any computer.  Access to
  348.     memory is one of the fastest.  MAXFiles is designed to speed up
  349.     your programs by transferring as many disk operations as
  350.     possible from the disk drive into expanded memory.
  351.  
  352.     MAXFiles is simple to learn.  You open or create the files you
  353.     want to work with and read from them or write to them using a
  354.     set of routines that are very similar to the file commands you
  355.     would use with OPEN FOR BINARY files in PB.
  356.  
  357.     Here's a list of the MAXFiles routines that have close
  358.     counterparts in PowerBASIC:
  359.  
  360.  
  361.        OpenX% ................ OPEN (...FOR BINARY)
  362.        SetAccessCode ......... ACCESS LOCK/UNLOCK/READ/WRITE, etc.
  363.        CloseX ................ CLOSE# (close one open file)
  364.        ClearX ................ CLOSE  (close all open files)
  365.        PutX .................. PUT  (as a file statement)
  366.        GetX .................. GET  (as a file statement)
  367.        PutStX ................ PUT$
  368.        GetStX ................ GET$
  369.        SaveX ................. BSAVE
  370.        LoadX ................. BLOAD
  371.        GetLineX$ ............. LINE INPUT#
  372.        EndX% ................. EOF  (used only with GetLineX$)
  373.        GetLocX& .............. SEEK (as a function)
  374.        SetLocX ............... SEEK (as a statement)
  375.        SizeX& ................ LOF
  376.        KillX ................. KILL
  377.        FlushX ................ FLUSH
  378.        ErrorCode% ............ ERR
  379.        SetErrorCode .......... ERROR
  380.        SetPtrBase ............ OPTION BASE
  381.  
  382.  
  383.  
  384.     MAXFiles also includes the following commands that have no close
  385.     equivalent in BASIC:
  386.  
  387.  
  388.        InitMAXFiles .......... initializes MAXFiles
  389.        ClipX ................. truncates a file
  390.        GetPtrBase% ........... returns value set by SetPtrBase
  391.        HandleX% .............. returns latest handle opened
  392.        SaveLineX ............. allows GetLineX to read multiple files
  393.        SetBufferSize ......... sets size of buffer used by GetLineX
  394.        SetDiskFile ........... (dis/en)ables use of EMS memory
  395.  
  396.  
  397.  
  398.     To use MAXFiles, you must call InitMAXFiles once, before you
  399.     call any other routines.  If you do not, MAXFiles will not use
  400.     EMS, but will only use ordinary disk i/o.  Typically, the top
  401.     few lines of a program using MAXFiles look like this:
  402.  
  403.  
  404.        $LINK "MAXLIB.PBL"        'include the MAXLIB library
  405.        $INCLUDE "MAXLIB.BI"      'include the declarations file
  406.        InitMAXFiles              'initialize MAXFiles
  407.  
  408.  
  409.     Among other things, InitMAXFiles determines what sort of EMM
  410.     driver is on the host machine.  If there is no EMM driver, or if
  411.     the driver has a version number prior to v4.0, the files you
  412.     open with MAXFiles will be ordinary disk files.
  413.  
  414.     As with BASIC, with MAXFiles you must open files before you can
  415.     use them.  To open a file, you use the command OpenX%.  The
  416.     command looks like this:
  417.  
  418.  
  419.         FileSpec$ = "D:\SUBDIR\FILENAME.EXT"
  420.         Handle% = OpenX%(FileSpec$)
  421.  
  422.  
  423.     If there is enough expanded memory to hold the entire file,
  424.     OpenX% copies the file into expanded memory and returns a handle
  425.     for the file, similar to a file number in BASIC.
  426.  
  427.     On the other hand, if there isn't any expanded memory on the
  428.     host machine, or if there isn't enough to hold the entire file,
  429.     OpenX% opens the file as a disk file and passes the DOS file
  430.     handle back to your program.
  431.  
  432.     You MUST keep track of the handle OpenX% returns.  You will
  433.     refer to the file using this handle, in much the same way you
  434.     refer to a file opened in BASIC by its file number.
  435.  
  436.     Once a file is opened, you can use other commands from MAXFiles
  437.     to read from it or write to it, get its size, find its pointer,
  438.     move its pointer, or close it.
  439.  
  440.     Here's an example.  Suppose you want to open a file full of long
  441.     integers and read individual long integers from it, as randomly
  442.     requested by the user.  The following code shows how that might
  443.     look in BASIC:
  444.  
  445.  
  446.         FileName$ = "C:\DATA\LONGINT.DAT"       ' set file spec
  447.         FileNum% = FREEFILE                     ' get file number
  448.         OPEN FileName$ FOR BINARY AS FileNum%   ' open the file
  449.         Bytes& = LOF(FileNum%)                  ' get the size
  450.         NumRecords% = Bytes& \ 4                ' calculate records
  451.  
  452.         DO
  453.           LINE INPUT "Enter record number: "; Record$
  454.           IF LEN(Record$) = 0 THEN EXIT LOOP
  455.           RecordNum% = VAL(Record$) - 1         ' convert to zero-based
  456.  
  457.           SEEK FileNum%, (RecordNum% * 4)       ' set the pointer
  458.           GET FileNum%, , RecordVal&            ' get the value
  459.           PRINT "That record is" ; RecordVal&   ' report it
  460.         LOOP
  461.  
  462.         CLOSE FileNum%                          ' close file
  463.  
  464.  
  465.  
  466.     Here is the same code, written for MAXFiles:
  467.  
  468.  
  469.  
  470.         FileName$ = "C:\DATA\LONGINT.DAT"       ' set file spec
  471.         FileNum% = OpenX%(FileName$)            ' open the file
  472.         Bytes& = SizeX&(FileNum%)               ' get the size
  473.         NumRecords% = Bytes& \ 4                ' calculate records
  474.  
  475.         DO
  476.           LINE INPUT "Enter record number: "; Record$
  477.           IF LEN(Record$) = 0 THEN EXIT LOOP
  478.           RecordNum% = VAL(Record$) - 1         ' convert to zero-based
  479.  
  480.           SetLocX FileNum%, (RecordNum% * 4&)   ' set the pointer
  481.           GetX FileNum%, 4&, RecordVal&         ' get the value
  482.           PRINT "That record is" ; RecordVal&   ' report it
  483.         LOOP
  484.  
  485.         CloseX FileNum%                         ' close file
  486.  
  487.  
  488.     You can see how closely the two examples resemble one another.
  489.  
  490.     As a rule, MAXFiles treats files as binary files, but there is
  491.     one obvious exception to this rule: text files.  Because they
  492.     are difficult to read using purely binary methods, MAXFiles
  493.     includes the command GetLineX$, for reading text files one line
  494.     at a time, like BASIC's LINE INPUT# command.  It comes with its
  495.     own substitute for EOF, too, called EndX%.
  496.  
  497.     You call GetLineX$ in a loop, like this:
  498.  
  499.  
  500.         Handle% = OpenX%("TEXTFILE.TXT")
  501.         DO
  502.            TextArray$(X%) = GetLineX$(Handle%)
  503.            INCR X%
  504.         LOOP UNTIL EndX%
  505.  
  506.  
  507.     Reading a text file is just that simple.
  508.  
  509.     Normally, when you append data to an EMS file there will be
  510.     enough expanded memory to hold it.  But sometimes there simply
  511.     won't be any more expanded memory available to hold the new
  512.     data.  In those cases, MAXFiles will convert the EMS file to a
  513.     disk file, on the fly.
  514.  
  515.     IMPORTANT: When MAXFiles converts an EMS file into a disk file
  516.     on the fly, the value of the Handle% variable will be changed,
  517.     too.  From then on, all references to the file must use the new
  518.     value in Handle%.  This may cause problems if your program
  519.     maintains secondary copies of the Handle% variable.
  520.  
  521.     Overall, if you are comfortable with binary file handling in
  522.     BASIC, you should have no trouble adapting to MAXFiles.  Even
  523.     so, one topic where you might need extra guidance is error
  524.     handling with MAXFiles.  For more information, see the chapter
  525.     on HANDLING ERRORS.
  526.  
  527.     If you are not familiar with binary file handling and file
  528.     pointers, see the chapter ABOUT FILE POINTERS.
  529.  
  530.     Lastly, before you use MAXFiles to read from or write to HUGE
  531.     arrays, you should read the chapter AVOIDING PROBLEMS WITH HUGE
  532.     ARRAYS.
  533.  
  534.  
  535.  
  536.  
  537.     GETTING STARTED WITH MAXARRAY
  538.  
  539.  
  540.     The information in this section is designed to get you started
  541.     with MAXArray.  Consult MAXLIB.REF to get answers to specific
  542.     questions about how each routine works.
  543.  
  544.     Arrays are a central part of most programs.  They are easy to
  545.     create and fast to access.  But sometimes you want to make more
  546.     arrays or larger arrays than will fit in conventional memory.
  547.     MAXArray can help to solve those problems.
  548.  
  549.     MAXArray is simple to use.  You create the arrays you want to
  550.     work with and read from them or write to them using a set of
  551.     routines that are very similar to the commands you would use to
  552.     manipulate arrays in BASIC.
  553.  
  554.     Using MAXArray you can create arrays in expanded memory in which
  555.     you can store or retreive numeric or TYPE variables, as well as
  556.     fixed-length string variables.  However, MAXArray cannot store
  557.     or retrieve variable length strings or flex strings.
  558.  
  559.     Here's a list of the MAXFiles routines that have close
  560.     counterparts in PowerBASIC:
  561.  
  562.  
  563.        DimEMS% ............... DIM
  564.        InEMS ................. Array(Index) = Variable
  565.        OutEMS ................ Variable = Array(Index)
  566.        EraseEMS .............. ERASE
  567.        RedimEMS .............. REDIM
  568.        LBoundEMS% ............ LBOUND
  569.        UBoundEMS% ............ UBOUND
  570.        BytesFreeEMS& ......... FRE
  571.        ErrorCode% ............ ERR
  572.        SetErrorCode .......... ERROR
  573.  
  574.  
  575.     In addition, MAXArray has many routines that have no counterpart
  576.     in ordinary BASIC.
  577.  
  578.  
  579.        InitMAXArray .......... initializes MAXArray routines
  580.        ArrayInEMS ............ copies conventional array to EMS
  581.        ArrayOutEMS ........... copies EMS to conventional array
  582.        ClearEMS .............. erases/deallocates all EMS arrays
  583.        FileInEMS ............. copies entire file to EMS array
  584.        FileOutEMS ............ copies entire EMS array to file
  585.        HandlesEMS% ........... returns max number of undimmed arrays
  586.        VersionEMS% ........... returns version number of EMM driver
  587.  
  588.  
  589.     To use MAXArray you must call InitMAXArray once, before you call
  590.     any other routines.  Unless you call InitMAXArray the routines
  591.     in MAXArray cannot function.
  592.  
  593.     Typically, the top few lines of a program using MAXArray look
  594.     like this:
  595.  
  596.  
  597.          $LINK "MAXLIB.PBL"        'include the MAXFiles OBJ code
  598.          $INCLUDE "MAXLIB.BI"      'include the declarations file
  599.          InitMAXArray              'initialize MAXArray
  600.  
  601.  
  602.     The next step in using MAXArray is to dimension an array and
  603.     put data into it.  Suppose you want to dimension an array of 100
  604.     double precision numbers, and set the value of the 100th element
  605.     to 2.77777.  Your code might look like this in BASIC:
  606.  
  607.  
  608.         DIM DoubleArray# (1 TO 100)           ' dim array
  609.         DblVal# = 2.77777
  610.         DoubleArray#(100) = DblVal#           ' set value
  611.  
  612.  
  613.     Here's the same code written using MAXArray:
  614.  
  615.  
  616.         DoubleArray% = DimEMS%(1, 100, 8)     ' dim array
  617.         DblVal# = 2.77777
  618.         InEMS DoubleArray%, 100, DblVal#      ' set value
  619.  
  620.  
  621.     As you see, to dimension an EMS array using DimEMS you must know
  622.     the length (in bytes) of the elements of the array you are
  623.     dimensioning.
  624.  
  625.     With ordinary BASIC you do not need to know that each element in
  626.     a double precision array takes 8 bytes of storage space.  DimEMS
  627.     requires this information.  Luckily, you can write code that
  628.     this information very simply, by using the LEN command.
  629.  
  630.     Most BASIC programmers know that LEN will return the length of a
  631.     string.  Many of them do not know that LEN can be used with
  632.     variables other than strings.  For instance:
  633.  
  634.  
  635.         DblLen% = LEN(DblVar#)
  636.  
  637.  
  638.     In this example, DbleLen% will equal 8, which is the number of
  639.     bytes needed to store a double precision variable.  LEN also
  640.     works with TYPE variables, fixed length strings and all numeric
  641.     variables.
  642.  
  643.     In ordinary BASIC, you identify an array by its name.  In
  644.     MAXArray, you identify an array by the handle passed back to
  645.     your program by DimEMS.  To give your array a name, just give
  646.     the handle variable the same name you want to give to the array.
  647.  
  648.     To assign a value to an array element in MAXFiles, you use
  649.     InEMS.  To assign a value to a variable from an array element,
  650.     you use OutEMS.  I have given the order of the parameters in
  651.     each of these commands the same order as their counterpart code
  652.     in BASIC, to help you remember. Here's how they compare:
  653.  
  654.  
  655.         Variable = ArrayName(Element)           'BASIC
  656.         OutEMS Variable, ArrayHandle, Element   'MAXArray
  657.  
  658.         ArrayName(Element) = Variable           'BASIC
  659.         InEMS ArrayHandle, Element, Variable    'MAXArray
  660.  
  661.  
  662.     Once you know how to dimension arrays in EMS using DimEMS, and
  663.     how to store or retrieve values in those arrays using InEMS and
  664.     OutEMS, you know enough to start using MAXArray.  But there is
  665.     more.
  666.  
  667.     To erase an array when it is no longer needed, use the command
  668.     EraseEMS.  To erase every array you have dimensioned, all at
  669.     once, use the command ClearEMS.  In most cases, this command
  670.     (ClearEMS) will also be called automatically as your program
  671.     ends, so you won't need to worry about deallocating the EMS
  672.     memory your program has allocated through MAXArray.
  673.  
  674.     If you discover that the array you have dimensioned is too small
  675.     or too large to hold the data you want to store, you can use
  676.     RedimEMS to make the array larger (or smaller) without erasing
  677.     it.  Unlike the REDIM command in PowerBASIC, data in the EMS
  678.     arrays you redimension will be preserved.
  679.  
  680.     MAXArray also provides routines to help you determine whether or
  681.     not sufficient EMS resources are available to meet your needs.
  682.     These routines are functions, called BytesFreeEMS, HandlesEMS
  683.     and VersionEMS.
  684.  
  685.     VersionEMS% returns a zero when there is no EMM driver
  686.     installed.  Otherwise it returns the driver's version number as
  687.     an integer, where 40 means version 4.0.
  688.  
  689.     BytesFreeEMS& returns a long integer telling how many bytes of
  690.     EMS memory are currently unallocated and available to use.
  691.  
  692.     HandlesEMS% returns the number of unused handles in an internal
  693.     table maintained by MAXArray.  You can only dimension as many
  694.     arrays as there are handles, and when HandlesEMS% returns a zero
  695.     you can't dimension another array unless you erase another array
  696.     that is already dimensioned.
  697.  
  698.     You can also use MAXArray to copy entire arrays to or from files
  699.     or to and from conventional memory.  To learn how, consult the
  700.     entries for FileinEMS/FileOutEMS and ArrayInEMS/ArrayOutEMS in
  701.     MAXLIB.REF.
  702.  
  703.     This short introduction should give you enough information to
  704.     get started with MAXArray.  I also recommend that you read the
  705.     chapters HANDLING ERRORS, and AVOIDING PROBLEMS WITH HUGE
  706.     ARRAYS.
  707.  
  708.  
  709.  
  710.  
  711.     HANDLING ERRORS
  712.  
  713.  
  714.     The usual method of error handling in BASIC requires that you
  715.     use some variation of the ON ERROR statement.  I have always
  716.     found ON ERROR to be cumbersome, code-bloating and difficult to
  717.     program.  Even PowerBASIC's own manual (p.288) suggests that you
  718.     consider using a third party library.
  719.  
  720.     I think you will find the error trapping in MAXLIB to be simple
  721.     to understand and easy to use.  Whenever an error takes place
  722.     (including critical errors), the MAXLIB routine that was running
  723.     at the time of the error will store the error code in an
  724.     internal variable and return directly to your program.
  725.  
  726.     Your program must test the value of the error code variable in
  727.     order to find out whether an error has occured.  MAXFiles and
  728.     MAXArray share a single routine for reporting the value of
  729.     the error code variable.  Reasonably enough, the routine is
  730.     called ErrorCode%.
  731.  
  732.     The process of testing the value of an error code variable is
  733.     called polling.
  734.  
  735.  
  736.         Handle% = OpenX%(FileName$)
  737.            IF ErrorCode% THEN CALL HandleError...
  738.  
  739.  
  740.     In the above example, the code polls for an error directly after
  741.     opening a file, and if ErrorCode% reports an error the code
  742.     calls a SUB named HandleError.
  743.  
  744.     You can poll for errors as often or as seldom as you think
  745.     necessary.  If an error takes place in one MAXLIB routine and
  746.     your program calls several more routines before polling for an
  747.     error, the value of the error code variable will report the most
  748.     recent error to take place.
  749.  
  750.     The internal error code variable is initialized to zero only
  751.     once, at the beginning of your program.  Its value will remain
  752.     zero so long as no error takes place.
  753.  
  754.     However, when the first error takes place, the value of the
  755.     variable will change to reflect the error code, and it will
  756.     remain unchanged until one of two things intervenes to change
  757.     its value:
  758.  
  759.        1) another (different) error takes place, or
  760.        2) your program resets the value, using SetErrorCode
  761.  
  762.  
  763.     SetErrorCode is similar to the function ERROR in BASIC.  You may
  764.     use it to clear the error code variable back to zero like this:
  765.  
  766.  
  767.        SetErrorCode 0
  768.  
  769.  
  770.     SetErrorCode may also be used to simulate errors (for example,
  771.     during the testing of your error handler) by passing non-zero
  772.     values corresponding to error codes.  Then ErrorCode% will
  773.     report these values back to your program as errors:
  774.  
  775.  
  776.        SetErrorCode 2
  777.        IF ErrorCode% THEN ....    'ErrorCode% always returns 2 here
  778.  
  779.  
  780.     A list of error codes and what they mean can be found in the
  781.     file ERRCODE.LST.  It includes descriptions of several
  782.     non-standard error codes that might be returned by MAXLIB
  783.     routines.  (They are: -1 through -4.)
  784.  
  785.     Because MAXLIB For PB requires your program to poll for errors,
  786.     the error handling in MAXLIB For PB is roughly the same as ON
  787.     ERROR RESUME NEXT used with ERR, in this fashion:
  788.  
  789.  
  790.         ON ERROR RESUME NEXT             'if error happens keep going
  791.         .
  792.         .
  793.         OPEN FileName$ FOR BINARY AS #1  'an error might happen here
  794.            IF ERR THEN                   'see if an error occured
  795.               CALL ErrorHandler          'if so, go handle it
  796.  
  797.  
  798.  
  799.     The equivalent code in MAXLIB would be:
  800.  
  801.  
  802.         FileNum% = OpenX%(FileName$)     'an error might happen here
  803.            IF ErrorCode% THEN            'see if an error occured
  804.               CALL ErrorHandler          'if so, go handle it
  805.  
  806.  
  807.     It is important to realize that MAXLIB For PB won't handle
  808.     errors for you.  What MAXLIB For PB will do is trap the error
  809.     and let you know which error it was.  To handle errors actively,
  810.     you must use an error handler in your program.
  811.  
  812.     The writing of an error handler is not difficult to understand.
  813.     A typical error handler will consist of a SELECT CASE structure
  814.     in which the various errors you anticipate are grouped according
  815.     to the various messages you want to display or actions you want
  816.     your program to take.
  817.  
  818.  
  819.         SELECT CASE ErrorCode%
  820.            CASE 2
  821.               PRINT  "File not found."
  822.            CASE 3
  823.               PRINT  "Path not found."
  824.            CASE 4
  825.            .
  826.            .
  827.            CASE ELSE
  828.               PRINT  "Unknown error. Error code:"; ErrorCode%
  829.         END SELECT
  830.  
  831.  
  832.     At the very least, an error handler reports error codes along
  833.     with descriptive messages.  A more comprehensive error handler
  834.     will allow your program the chance to resolve the error, or to
  835.     shut down gracefully and save your data if possible.
  836.  
  837.  
  838.  
  839.  
  840.  
  841.     GENERAL TOPICS
  842.  
  843.  
  844.     The following section covers several topics of general interest
  845.     to programmers using MAXLIB For PB in their programs, including
  846.     information about some problems you might encounter when using
  847.     MAXLIB For PB, and how to avoid them.
  848.  
  849.  
  850.  
  851.  
  852.     ABOUT FILE POINTERS
  853.  
  854.  
  855.     It is possible to program in BASIC without ever learning about
  856.     file pointers.  However, MAXFiles requires that you understand
  857.     file pointers, so if you are unfamiliar with them, please read
  858.     this section.
  859.  
  860.     NOTE: DOS, PB and MAXFiles all consider a file's first byte to
  861.     be byte zero rather than byte 1. Although MAXFiles does let you
  862.     choose the one-based convention, this section will use the
  863.     zero-based convention throughout.
  864.  
  865.     Think of a file pointer as an invisible finger pointing at the
  866.     exact byte where MAXFiles will begin to read from or write to a
  867.     file.  It will move itself as you read (or write), like a finger
  868.     following text on the page of a book.  As you stop reading (or
  869.     writing) the finger stops itself one byte beyond the last byte
  870.     read (or written).
  871.  
  872.     When a file is first opened the pointer is at the first byte of
  873.     the file: byte zero.  If you start writing to a file right after
  874.     opening it, you will start writing at byte zero.  And if any
  875.     data is in the file it will be overwritten by the new data,
  876.     starting with byte zero.
  877.  
  878.     Luckily, you can move the pointer anywhere you want, anytime you
  879.     want.  For the sake of simplicity, let's suppose you have a file
  880.     that is four bytes long and you want to append some data to the
  881.     end of this file.  The four bytes would run from zero to 3:
  882.  
  883.  
  884.        BYTES:  0  1  2  3
  885.                ^
  886.  
  887.     Since you have just opened the file, the pointer (^) is at byte
  888.     zero.  Before you can append data to the end of a file, the
  889.     pointer must point one byte beyond the file's last byte.  In
  890.     this case the last byte is byte 3, and one byte beyond byte 3 is
  891.     byte 4.
  892.  
  893.     To move a pointer for appending data, first you need to know how
  894.     long the file is.  In BASIC you could use LOF, but in MAXFiles
  895.     you would use SizeX&, like so:
  896.  
  897.  
  898.        Handle% = OpenX%(FileName$)
  899.        Size& = SizeX&(Handle%)
  900.  
  901.  
  902.     In this case, Size& will equal 4, because our file is four bytes
  903.     long.  And, conveniently, the byte that is one byte past the end
  904.     is byte 4. You may move the pointer to byte 4, using SetLocX:
  905.  
  906.  
  907.        Size& = SizeX&(Handle%)    'Size& = 4
  908.        SetLocX Handle%, Size&     'pointer is at byte 4
  909.  
  910.  
  911.     Now our file looks like this:
  912.  
  913.  
  914.        BYTES:  0  1  2  3 (4)
  915.                            ^
  916.  
  917.     I put the 4 in parentheses because it really doesn't "belong to"
  918.     our file yet, even though the pointer points there.  Now, if we
  919.     write something to our file, no old data will be overwritten.
  920.  
  921.     Now let's write some data to our file and see what happens.  To
  922.     write data, you can use PUT in BASIC.  In MAXFiles you could use
  923.     PutX.  This is how you'd write an integer to the file:
  924.  
  925.  
  926.        PutX Handle%, 2&, Variable%
  927.  
  928.  
  929.     This writes 2 bytes to the end of our file, so it looks like
  930.     this:
  931.  
  932.  
  933.        BYTES:  0  1  2  3  4  5  (6)
  934.                                   ^
  935.  
  936.     Now there are six bytes in our file (0-5) and the pointer has
  937.     moved to byte 6. The pointer moves each time we write OR read
  938.     bytes.  It moves exactly one byte forward for every byte we read
  939.     or write.
  940.  
  941.     Those last two sentences are VERY important:
  942.  
  943.     * The pointer moves each time you write OR read bytes.  It moves
  944.     exactly one byte forward for every byte you read or write. *
  945.  
  946.     If you do not know where the pointer is, you can get into big
  947.     trouble.  To avoid such trouble you can always ask where the
  948.     pointer is by calling GetLocX&.  Just remember that when
  949.     GetLocX& tells you the pointer is at byte 1, it is referring to
  950.     the second byte of the file.
  951.  
  952.     That covers all you need to know about file pointers.  All in
  953.     all, file pointers allow you to read or write anywhere you want
  954.     in a file.  You can open a file, read a few bytes, jump
  955.     somewhere, write over some other bytes, jump to the end, tack on
  956.     some bytes there, then jump back to the start - all without
  957.     having to close and reopen your file.
  958.  
  959.     You are not required to having same-length records.  You are not
  960.     required to start at the front and plow straight to the end.
  961.     You can order your data anyway you like and put it anywhere
  962.     that's convenient, just by jumping the pointer there.
  963.  
  964.  
  965.  
  966.  
  967.     ABOUT EXPANDED MEMORY
  968.  
  969.  
  970.     This chapter gives you a quick overview of expanded memory and
  971.     how it works.  If you are already familiar with EMS, you may
  972.     skip this section.
  973.  
  974.     The first verison of EMS was version 3.0.  More precisely,
  975.     versions prior to 3.0 were not made public.  As of this writing,
  976.     the EMS specification is in version 4.0 and it looks likely to
  977.     stay there.
  978.  
  979.     All manipulation of EMS memory is accomplished through calls to
  980.     an EMM driver, a piece of software loaded through CONFIG.SYS.
  981.     Calls to the EMM driver are made through interrupt &H67.  One
  982.     common EMM driver is EMM386.SYS.  It has been distributed with
  983.     DOS since v5.0.  Without a driver, EMS can't be used, even if it
  984.     is installed.
  985.  
  986.     EMS requires that one 64K segment be set aside for its exclusive
  987.     use, in the memory area starting at D000:0000 or E000:0000.
  988.     This 64K segment is subdivided into 4 areas of 16K each,
  989.     numbered 0-3.  These areas are sometimes called "frames".
  990.  
  991.     To use expanded memory, you must allocate it first.  Normally,
  992.     EMS memory is allocated 16K bytes at a time.  This is the method
  993.     used by MAXLIB For PB.  Each 16K chunk of memory is called a
  994.     "page".  It is no accident that pages and frames are the same
  995.     size.
  996.  
  997.     You may allocate a group of many pages or just a single page.
  998.     The group is assigned a handle, like a file handle.  Most calls
  999.     to the EMM driver require that you refer to this handle.
  1000.  
  1001.     The first page in a group is called page 0, the next is page 1,
  1002.     and so on.  At the hardware level, no two pages in a single
  1003.     group need to be stored in contiguous memory.  They can be
  1004.     scattered all over the physical address space of the EMS memory.
  1005.     But the driver takes care of that detail for you.  As far you
  1006.     know, page 0 comes first, page 1 comes next.  Sometimes
  1007.     ignorance is bliss!
  1008.  
  1009.     Before you can write to or read from any of the pages you have
  1010.     allocated, the page must first be "mapped" into a frame.  This
  1011.     is done by calling the EMM driver.  Once a page is mapped into a
  1012.     frame, the whole contents of the EMS page are copied into the
  1013.     memory that resides inside that frame.  After this is done, any
  1014.     alteration to the memory inside the frame will be reflected in
  1015.     the memory of the page.
  1016.  
  1017.     Since only 4 frames exist, but a much larger number of pages may
  1018.     exist, pages generally must be shuffled in and out of these
  1019.     frames (a lot).  This scheme is called "bank switching" and it
  1020.     has been around a long time.
  1021.  
  1022.     One peculiarity of EMS memory is the fact that it will not be
  1023.     deallocated as your program ends.  Program memory (the famed
  1024.     first 640K) is automatically released by DOS when a program
  1025.     ends, unless the program is a TSR.  But EMS memory remains
  1026.     allocated to the same handle until you actively deallocate it by
  1027.     calling the EMM driver.
  1028.  
  1029.     A program that allocates EMS and ends without releasing it, can
  1030.     effectively prevent any subsequent programs from using that EMS
  1031.     memory.  To prevent this from happening in your programs, MAXLIB
  1032.     For PB will automatically deallocate all the EMS memory you have
  1033.     allocated with them, as your program ends.  For more details
  1034.     about this, see ClearX and ClearEMS in MAXLIB.REF.
  1035.  
  1036.  
  1037.  
  1038.  
  1039.  
  1040.     ABOUT DOS STDXXX DEVICES
  1041.  
  1042.  
  1043.     Each time your computer boots, DOS opens a set of 5 handles,
  1044.     numbered 0-4.  These handles are assigned to 5 standard devices.
  1045.     DOS uses these handles to access the devices for its own input
  1046.     and output.  They are:
  1047.  
  1048.  
  1049.        Device:      Handle:      Initialized as:
  1050.        -------      -------      ---------------
  1051.         STDIN          0            Keyboard
  1052.         STDOUT         1             Screen
  1053.         STDERR         2             Screen
  1054.         STDAUX         3           Com port 1
  1055.         STDPRN         4          Printer (LPT1)
  1056.  
  1057.  
  1058.  
  1059.     Because MAXFiles uses the same handle-based services that DOS
  1060.     uses, you can take advantage of these STDxxx devices by passing
  1061.     their handles to the various MAXFiles routines.
  1062.  
  1063.     You should realize that using DOS devices can be a crude method
  1064.     of input and output.  Only in a few situations will there be any
  1065.     advantage to using them, and in many cases there will be
  1066.     disadvantages.  Most especially, I would NOT recommend using
  1067.     MAXFiles with STDAUX as a replacement for the built-in
  1068.     communications ability of PowerBASIC!
  1069.  
  1070.     However, two examples come quickly to mind where a STDxxx device
  1071.     has an advantage over using BASIC's own commands.  One is where
  1072.     you want to direct your program's output through the ANSI.SYS
  1073.     device driver.  The other is when you want to be able to
  1074.     redirect or pipe input or output from the command line.
  1075.  
  1076.     To output a string to the screen through DOS services, you could
  1077.     use BASIC code similar to this:
  1078.  
  1079.  
  1080.        OPEN "CONS:" FOR OUTPUT AS #1
  1081.        OutPut$ = "This will reach the screen via DOS."
  1082.        PRINT #1, OutPut$
  1083.  
  1084.  
  1085.     The MAXFiles equivalent would be this:
  1086.  
  1087.  
  1088.        %STDOUT = 1
  1089.        OutPut$ = "This will reach the screen via DOS."
  1090.        PutStX %STDOUT, OutPut$ + CHR$(13,10)
  1091.  
  1092.  
  1093.     In this example, OutPut$ would be (normally) be written to the
  1094.     screen by DOS.  If DOS redirection were in effect, the string
  1095.     would be output to the device or file indicated by the
  1096.     redirection symbol on the command line, instead of to the
  1097.     screen.
  1098.  
  1099.     If OutPut$ included ANSI escape codes, routing OutPut$ through
  1100.     DOS makes it available to interpretation by ANSI.SYS.
  1101.  
  1102.     Most of the routines in MAXFiles will accept STDxxx handles,
  1103.     with two exceptions.  CloseX will not close a handle numbered
  1104.     0-4, and GetLineX$, because of its internal buffer and internal
  1105.     pointer, cannot accept a DOS device handle, either.
  1106.  
  1107.     Overall, if you require DOS redirection in your programs, you
  1108.     should be able to swing it, using just the routines in MAXFiles.
  1109.     But it may take some experimentation.  For more information
  1110.     about DOS STDxxx devices, you should consult a good DOS
  1111.     reference.
  1112.  
  1113.  
  1114.  
  1115.  
  1116.     AVOIDING PROBLEMS WITH HUGE ARRAYS
  1117.  
  1118.  
  1119.     HUGE arrays are larger than a single 64K segment.  PowerBASIC
  1120.     3.0 lets you create HUGE arrays where the length of each element
  1121.     is not a power of two (the length is not 2,4,8,16...etc).
  1122.  
  1123.     To accomplish this feat the PowerBASIC compiler must recognize
  1124.     when the end of the current array segment does not contain
  1125.     enough bytes to hold a complete array element.
  1126.  
  1127.     Let's say you want to dimension an array of 1000 fixed length
  1128.     strings, where each string is 80 bytes long:
  1129.  
  1130.  
  1131.         DIM HUGE FixedStrings(1 TO 1000) AS STRING * 80
  1132.  
  1133.  
  1134.     The compiler can put 819 elements of 80 bytes each into the
  1135.     first 64K segment.  At that point the segment contains 65520
  1136.     bytes of data with only 16 bytes left in the segment.  That's
  1137.     not enough to hold a complete element, so the compiler will
  1138.     insert 16 "padding" bytes into the array at that point.  This
  1139.     permits element 820 to start at a new 64K segment boundary.
  1140.  
  1141.     In PowerBASIC, placing a discontinuity like this into the data
  1142.     is not a problem, because array elements are always accessed
  1143.     individually.
  1144.  
  1145.     Unlike PowerBASIC, MAXLIB For PB has routines that allow you to
  1146.     access entire arrays all at once.  These routines are GetX and
  1147.     PutX in MAXFiles, and ArrayInEMS and ArrayOutEMS in MAXArray.
  1148.  
  1149.     These commands always read data as a continuous series of bytes.
  1150.     If the compiler has stored the data in a discontinuous series of
  1151.     bytes, it causes problems.  In our example using the fixed
  1152.     length string array, a discontinuity of 16 bytes occurs between
  1153.     elements 819 and 820.
  1154.  
  1155.     To demonstrate the problem more clearly, let's say you want to
  1156.     save a copy of that HUGE fixed length string array into a file,
  1157.     using PutX.  It might seem natural to write code like this:
  1158.  
  1159.  
  1160.         FileName$ = "FIXSTRNG.DAT"
  1161.         SaveHandle% = OpenX%(FileName$) ' open a file to save into
  1162.  
  1163.         Bytes& = CLNG(80 * 1000)        ' calculate bytes to save
  1164.         PutX SaveHandle%, Bytes&, FixedStrings(1)    'save them
  1165.  
  1166.  
  1167.     This code contains a bug.  The problem comes in the third line,
  1168.     where we calculate how many bytes we need to write into the
  1169.     file.
  1170.  
  1171.     Yes, there are 80000 bytes of data to be read, but because of
  1172.     the 16 unused bytes that were inserted at the end of the first
  1173.     64K segment, those 80000 bytes of data are stored across 80016
  1174.     bytes of memory!
  1175.  
  1176.     The bug comes in, because PutX is not smart enough to skip over
  1177.     the 16 bytes of non-data inserted into the array.  Instead it
  1178.     will read those 16 bytes of padding into the file and it will
  1179.     not read the final 16 bytes of data.
  1180.  
  1181.     The easy way to work around this problem is to read each element
  1182.     individually, in a loop, and write each one to the file:
  1183.  
  1184.  
  1185.         FileName$ = "FIXSTRNG.DAT"
  1186.         SaveHandle% = OpenX%(FileName$) ' open a file to save into
  1187.  
  1188.         Bytes& = 80&                    ' read one element at a time
  1189.         FOR X% = 1 TO 1000
  1190.           PutX SaveHandle%, Bytes&, FixedStrings(X%)
  1191.         NEXT X%
  1192.  
  1193.  
  1194.     This is not the fastest solution possible, but it is by far the
  1195.     simplest.  It is not the fastest because it requires your
  1196.     program to access the disk 1000 times, instead of once.
  1197.  
  1198.     Another possible work around is to make the disk file 80016
  1199.     bytes long, so it contains all the data, along with the gap in
  1200.     the data.  Then you could load the resulting file directly into
  1201.     any HUGE array that is identical to the original array, because
  1202.     an identical array will have the same gap in the data, located
  1203.     in the same place!
  1204.  
  1205.     This last approach is rather inflexible, but it is certainly
  1206.     fast, since it uses the least number of disk reads or writes.
  1207.  
  1208.     If you are using ArrayInEMS and ArrayOutEMS instead of GetX and
  1209.     PutX, the range of solutions is even narrower.  Simply put, you
  1210.     cannot use ArrayInEMS or ArrayOutEMS with any HUGE array that
  1211.     has an element size which is not a power of two.  With such
  1212.     arrays, you must use InEMS and OutEMS one element at a time.
  1213.  
  1214.  
  1215.  
  1216.  
  1217.  
  1218.     SAFEGUARDING YOUR DATA
  1219.  
  1220.  
  1221.     This section is meant to help you to design your programs
  1222.     written with MAXLIB For PB to be as safe as possible.  The major
  1223.     concern is that any data that is stored in EMS will disappear
  1224.     without a trace when the power turns off.  In this respect
  1225.     expanded memory is just like conventional RAM.
  1226.  
  1227.     Data stored in EMS arrays using MAXArray should be considered to
  1228.     be as vulnerable as data kept in ordinary arrays.  There are no
  1229.     ways to make it safer.  With MAXFiles, however, there are some
  1230.     safeguards built in, and others you can add.
  1231.  
  1232.     Normally, as your program ends, MAXFiles ensures that every file
  1233.     you have opened is written safely to disk.  However, power
  1234.     surges, frozen keyboards, critical errors and other disruptions
  1235.     do happen, and you should design your program around their
  1236.     possibility. This section tells you how.
  1237.  
  1238.     The first question you must ask is: how vital is this data?  I
  1239.     can't answer that one for you.  Among other things, you should
  1240.     consider whether the data can be reconstructed from existing
  1241.     data, and what portion of the data you could place at risk
  1242.     before the risk becomes unacceptable.
  1243.  
  1244.     The second question is: how can I make my data as safe as
  1245.     possible, using MAXFiles?  I will try to answer that one.
  1246.  
  1247.     For files that absolutely MUST be written to a physical disk as
  1248.     quickly as possible, MAXFiles gives you the option of forcing a
  1249.     particular file to be opened as a disk file.  The command for
  1250.     this is called SetDiskFile.
  1251.  
  1252.     When you call SetDiskFile with a non-zero value, the next file
  1253.     opened and all subsequent files will be disk files.  To permit
  1254.     MAXFiles to open EMS files again, call SetDiskFile once more,
  1255.     passing it a zero value.
  1256.  
  1257.  
  1258.  
  1259.         SetDiskFile 1                     'force disk-only
  1260.         Handle% = OpenX%("importnt.dat")  'open as a disk file
  1261.         SetDiskFile 0                     'resume default setting
  1262.  
  1263.  
  1264.  
  1265.     There is another, less drastic tool you can use to safeguard
  1266.     important data, while preserving the speed and convenience of
  1267.     letting MAXFiles manage your files in EMS.  It is called FlushX.
  1268.  
  1269.     When you call FlushX with the handle for an EMS file, FlushX
  1270.     will open a disk file and copy the entire current contents of
  1271.     that file from expanded memory onto disk.  It does this very
  1272.     rapidly.  Then the disk file is closed, which flushes the
  1273.     contents of any DOS buffers to disk as well.
  1274.  
  1275.     The drawback to FlushX is that writing an entire file to disk,
  1276.     even quite rapidly, is relatively slow.  Calling FlushX every
  1277.     time data is added to a file will completely defeat the purpose
  1278.     for using EMS in the first place - speed.  Such a strategy would
  1279.     be slower than simply opening a disk file and writing to it
  1280.     incrementally.
  1281.  
  1282.     A more successful strategy for using FlushX might be to call it
  1283.     at every 100th iteration of a loop.  Or you could invoke ON
  1284.     TIMER and call it every time a certain interval had passed.
  1285.     Only you can decide how to use this tool.  But it is there to be
  1286.     used if you need it.
  1287.  
  1288.     Bear in mind that these precautions are most applicable when a
  1289.     file has been opened as an EMS file.  Because MAXFiles will
  1290.     function perfectly well on computers having no EMS, you may want
  1291.     to determine whether a particular file has been opened as an EMS
  1292.     file or a disk file.
  1293.  
  1294.     To see if a file was opened as an EMS file or a disk file,
  1295.     examine the handle passed back by OpenX%.  A file stored in EMS
  1296.     will have a handle greater than 255.  A disk file will have a
  1297.     handle less than 255.
  1298.  
  1299.